<?php

namespace App\Services\Sales;
use App\Common\BnFormatConfig;
use App\Common\Tools;
use App\Exceptions\BusinessException;
use App\Common\Constant;
use App\Common\ResponseCode;
use App\Models\Sales\OrderPay;
use App\Models\Sales\Orders;
use App\Params\H5\OrderCommentParams;
use App\Params\H5\OrderCreateParams;
use App\Params\H5\OrderListParams;
use App\Params\H5\OrderPayParams;
use App\Repository\AddressRepository;
use App\Repository\CartRepository;
use App\Repository\CustomerCouponRepository;
use App\Repository\CustomerRepository;
use App\Repository\GoodsRepository;
use App\Repository\OrderPayRepository;
use App\Repository\OrderRepository;
use App\Services\BaseService;
use App\Traits\Calculator;
use App\Traits\DateTimeTrait;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * 订单相关业务类
 *
 * @author WangBin
 * @date 2021-09-24
 * @package App\Http\Services\Sales
 */
class OrderService extends BaseService
{
    use Calculator, DateTimeTrait;

    /**
     * 获取中台订单列表
     *
     * @param \App\Params\Backend\OrderListParams $filter
     * @return array
     */
    public function getAdminOrderList(\App\Params\Backend\OrderListParams $filter)
    {
        $orders = OrderRepository::getInstance()->getList($filter->toArray());
        $result = $this->toList($orders, $filter->getPage(), $filter->getPageSize());
        // 转换数据
        collect($result['list'])->each(function ($item){
            $item->status_name = Constant::ORDER_STATUS_MAP[$item->status];
            $item->pay_status_name = Constant::PAY_STATUS_MAP[$item->pay_status];
            $item->pay_method_name = Constant::PAY_METHOD_MAP[$item->pay_method];
            $item->order_from = Constant::ORDER_FROM_MAP[$item->order_from];
            $item->buy_mode = Constant::ORDER_BUY_MODE_MAP[$item->buy_mode];
            $item->actions = OrderRepository::getInstance()->getAdminCanActions($item->status);
        });
        return $result;
    }

    /**
     * 获取中台订单详情
     *
     * @param int $orderId
     * @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
     */
    public function getAdminOrder(int $orderId)
    {
        $order = OrderRepository::getInstance()->getOrderInfo($orderId);
        return $order;
    }

    /**
     * 创建订单
     *
     * @param OrderCreateParams $params
     * @return array
     * @throws BusinessException
     */
    public function create(OrderCreateParams $params)
    {
        $result = ['order_id' => 0, 'order_bn' => '', 'pay_amount' => 0, 'pay_method' => $params->getPayType()];
        try {
            DB::beginTransaction();
            // 获取客户信息
            $customer = CustomerRepository::getInstance()->getById($params->getCustomerId(), true);
            if(is_null($customer)) {
                throw new \Exception('客户不存在');
            }
            // 获取结算数据
            $fastBuy = $params->getMode() != 'cart' ? 1 : 0;
            $checkoutData = CartRepository::getInstance()->getCheckoutGoods($params->getCustomerId(), $fastBuy);
            if(is_null($checkoutData)) {
                throw new \Exception('结算商品为空');
            }
            // 获取客户收货地址
            $address = AddressRepository::getInstance()->getByCustomerId($params->getCustomerId(), 1);
            if(is_null($address)) {
                throw new \Exception('收货地址不存在');
            }
            // 运费
            $expressAmount = 0;
            // todo

            // 优惠券优惠
            $couponDiscount = 0;
            $customerCoupon = CustomerCouponRepository::getInstance()->getSelected($customer->customer_id);
            if(!is_null($customerCoupon)) {
                $couponDiscount = $customerCoupon->discount;
            }

            // 营销活动优惠
            $promotionDiscount = 0;

            // 获取主订单数据
            $totalAmount = 0;
            $totalQty = 0;
            $checkoutData->each(function ($item) use (&$totalAmount, &$totalQty) {
                $totalAmount = $this->addNum($totalAmount, $item->total_amount);
                $totalQty = $this->addNum($totalQty, $item->qty_ordered);
            });
            // 总优惠金额
            $totalDiscount = $this->addNum($couponDiscount, $promotionDiscount);
            // 订单总金额
            $totalAmount = $this->addNum($totalAmount, $expressAmount);
            // 付款金额
            $payAmount = $this->sub($totalAmount, $totalDiscount);
            // 校验余额
            if($params->getPayType() == Constant::PAY_METHOD_BALANCE && $this->compare($customer->balance, $payAmount) < 0) {
                throw new \Exception("余额不足：余额({$customer->balance})");
            }

            $orderData = [
                'order_id' => Tools::nextId(),
                'customer_id' => $params->getCustomerId(),
                'customer_name' => $customer->nickname,
                'order_bn' => Tools::buildBn(BnFormatConfig::GOODS_BN_KEY),
                'order_from' => $params->getOrderFrom(),
                'status' => Constant::ORDER_STATUS_CREATED,
                'total_amount' => $totalAmount,
                'final_amount' =>$payAmount,
                'express_amount' => $expressAmount,
                'qty_ordered' => $totalQty,
                'total_count' => $checkoutData->count(),
                'pay_status' => Constant::PAY_STATUS_WAIT_PAY,
                'pay_method' => $params->getPayType(),
                'buy_mode' => $params->getMode(),
                'coupon_discount' => $couponDiscount,
                'promotion_discount' => $promotionDiscount,
                'total_discount' => $totalDiscount,
                'pay_amount' => $payAmount,
                'delivery_type' => Constant::DELIVERY_TYPE_EXPRESS,
                'consignee' => $address->contact_name,
                'mobile' => $address->mobile,
                'address' => $address->region . $address->full_address,
                'remo' => $params->getRemo()
            ];
            // 生成订单
            $orderId = OrderRepository::getInstance()->create($orderData);
            if(!$orderId) {
                throw new \Exception('主订单生成失败');
            }

            // 创建订单明细
            OrderRepository::getInstance()->createItem($orderId, $checkoutData->toArray());
            // 清除购物车结算商品
            CartRepository::getInstance()->removeCheckoutGoods($params->getCustomerId());
            if($params->getPayType() == Constant::PAY_METHOD_BALANCE) {
                // 扣除余额
                CustomerRepository::getInstance()->updateBalance($params->getCustomerId(), -$payAmount);
                // 更新订单已支付
                OrderRepository::getInstance()->update(['status' => Constant::ORDER_STATUS_PAYED, 'pay_status' => Constant::PAY_STATUS_PAYED, 'pay_at' => Carbon::now()->toDateTimeString()], $orderId);
            }
            // 更新优惠券状态为已使用
            if(!is_null($customerCoupon)) {
                CustomerCouponRepository::getInstance()->save(['used_at' => $this->getCurrDateTime()], $customerCoupon->entity_id);
            }
            // 保存订单支付单据
            OrderPayRepository::getInstance()->save([
                'pay_id' => Tools::nextId(),
                'customer_id' => $params->getCustomerId(),
                'nickname' => $customer->nickname,
                'order_id' => $orderId,
                'order_bn' => $orderData['order_bn'],
                'pay_bn' => Tools::buildBn(BnFormatConfig::ORDER_PAY_BN_KEY),
                'total_amount' => $totalAmount,
                'pay_amount' => $payAmount,
                'status' => OrderPay::ORDER_PAY_STATUS_2,
                'pay_at' => Tools::getDateTime(),
                'pay_channel' => OrderPay::ORDER_PAY_CHANNEL_1,
                'pay_type' => OrderPay::ORDER_PAY_TYPE_1
            ]);
            DB::commit();
            $result['order_id'] = $orderId;
            $result['order_bn'] = $orderData['order_bn'];
            $result['pay_amount'] = $orderData['pay_amount'];
        } catch (\Exception $exception) {
            DB::rollBack();
            Log::error('[创建订单] 出错：' . $exception->getMessage());
            throw new BusinessException(ResponseCode::ORDER_CREATE_FAIL, ['error' => $exception->getMessage()]);
        }
        return $result;
    }

    /**
     * 支付订单费用
     *
     * @param OrderPayParams $params
     * @return bool
     * @throws BusinessException
     */
    public function pay(OrderPayParams $params)
    {
        $result = false;
        try {
            DB::beginTransaction();
            // 获取待支付的订单
            $order = OrderRepository::getInstance()->getById($params->getOrderId(), true);
            // 订单状态
            if($order->status != Constant::ORDER_STATUS_CREATED) {
                throw new \Exception('订单不可支付');
            }
            // 获取客户
            $customer = CustomerRepository::getInstance()->getById($order->customer_id);
            // 校验余额
            if($params->getPayType() == Constant::PAY_METHOD_BALANCE && $this->compare($customer->balance, $order->pay_amount) < 0) {
                throw new \Exception("余额不足：余额({$customer->balance})");
            }
            // 修改订单状态
            // 扣除余额
            CustomerRepository::getInstance()->updateBalance($params->getCustomerId(), -$order->pay_amount);
            // 更新订单已支付
            OrderRepository::getInstance()->update(['status' => Constant::ORDER_STATUS_PAYED, 'pay_status' => Constant::PAY_STATUS_PAYED, 'pay_at' => Carbon::now()->toDateTimeString()], $params->getOrderId());
            $result = true;
            DB::commit();
        } catch (\Exception $exception) {
            DB::rollBack();
            Log::error("[订单支付] 出错：{$exception->getMessage()}");
            throw new BusinessException(ResponseCode::PAY_FAIL, ['error' => $exception->getMessage()]);
        }
        return $result;
    }

    /**
     * 客户订单数量统计
     *
     * @param int $customerId
     * @return array
     */
    public function getCustomerStat(int $customerId)
    {
        $result = ['wait_pay_num' => 0, 'wait_receive_num' => 0, 'wait_comment' => 0, 'aftersales_num' => 0, 'wait_delivery_num' => 0];
        $filter = ['customer_id' => [$customerId], 'start_date' => Carbon::parse('-30 days')->toDateTimeString()];
        $orders = OrderRepository::getInstance()->getList($filter)->get();
        foreach ($orders as $order)
        {
            switch ($order->status)
            {
                case Constant::ORDER_STATUS_CREATED:
                    $result['wait_pay_num'] += 1;
                    break;
                case Constant::ORDER_STATUS_PAYED:
                    $result['wait_delivery_num'] += 1;
                    break;
                case Constant::ORDER_STATUS_DELIVERY_PART:
                case Constant::ORDER_STATUS_DELIVERY_ALL:
                    $result['wait_receive_num'] += 1;
                    break;
                case Constant::ORDER_STATUS_FINISHED:
                    if($order->is_comment == 0) {
                        $result['wait_comment'] += 1;
                    }
                    break;
            }
        }
        return $result;
    }

    /**
     * 获取客户的订单
     *
     * @param OrderListParams $params
     * @return array
     */
    public function getCustomerOrderList(OrderListParams $params)
    {
        $filter = ['customer_id' => [$params->getCustomerId()]];
        if(!empty($params->getDataType()) && $params->getDataType() != 'all') {
            $filter['status'] = [$params->getDataType()];
            if($params->getDataType() == 'WAIT_COMMENT') {
                $filter['status'] = [Constant::ORDER_STATUS_FINISHED];
                $filter['is_comment'] = 0;
            }
        }
        $orders = OrderRepository::getInstance()->getList($filter);
        $result = $this->toList($orders, $params->getPage(), $params->getPageSize());
        $result['list']->each(function ($item){
            // 按钮显示
            $item->btns = OrderRepository::getInstance()->getCanActions($item->status);
            // 订单明细
            $item->items = OrderRepository::getInstance()->getItems($item->order_id);
            // 订单状态
            $item->status_name = Constant::ORDER_STATUS_MAP[$item->status];
        });
        return $result;
    }

    /**
     * 取消订单
     *
     * @param int $orderId
     * @return bool
     * @throws BusinessException
     */
    public function cancel(int $orderId)
    {
        $order = OrderRepository::getInstance()->getById($orderId, true);
        if(is_null($order)) {
            throw new BusinessException(ResponseCode::ORDER_NOT_FOUND);
        }
        if(!in_array($order->status, Constant::ORDER_STATUS_CAN_CANCEL)) {
            throw new BusinessException(ResponseCode::ORDER_STATUS_NOT_CANCEL);
        }
        $data = ['status' => Constant::ORDER_STATUS_CANCEL];
        return OrderRepository::getInstance()->update($data, $orderId);
    }

    /**
     * 删除订单
     *
     * @param int $orderId
     * @return bool
     * @throws BusinessException
     */
    public function delete(int $orderId)
    {
        $order = OrderRepository::getInstance()->getById($orderId);
        if(is_null($order)) {
            throw new BusinessException(ResponseCode::ORDER_NOT_FOUND);
        }
        if(!in_array($order->status, [Constant::ORDER_STATUS_CREATED, Constant::ORDER_STATUS_WAIT_PAY, Constant::ORDER_STATUS_CANCEL, Constant::ORDER_STATUS_FINISHED])) {
            throw new BusinessException(ResponseCode::ORDER_STATUS_NOT_DELETE);
        }
        $order->status = Constant::ORDER_STATUS_DELETED;
        if($order->save()) {
            return true;
        }
        return false;
    }

    /**
     * 获取客户订单详情
     *
     * @param int $orderId
     * @return Orders|\Illuminate\Database\Eloquent\Model|object|null
     * @throws BusinessException
     */
    public function getH5Order(int $orderId)
    {
        return OrderRepository::getInstance()->getOrderInfo($orderId);
    }

    /**
     * 获取订单初始化信息
     *
     * @return array
     */
    public function getInit()
    {
        return [
            'status_list' => Constant::ORDER_STATUS_FLOW_MAP,
        ];
    }

    /**
     * 确认收货
     *
     * @param int $orderId
     * @return int
     * @throws BusinessException
     */
    public function receipt(int $orderId)
    {
        $order = OrderRepository::getInstance()->getById($orderId);
        if(!in_array($order->status, Constant::ORDER_STATUS_CAN_RECEIPT)) {
            throw new BusinessException(ResponseCode::ORDER_STATUS_NOT_RECEIPT);
        }
        // 更新订单状态为订单完成
        OrderRepository::getInstance()->update(['status' => Constant::ORDER_STATUS_FINISHED, 'finished_at' => Carbon::now()], $orderId);
        return $orderId;
    }

    /**
     * 保存商品评论
     *
     * @param OrderCommentParams $params
     * @return bool
     * @throws BusinessException
     */
    public function comment(OrderCommentParams $params)
    {
        // 获取订单
        $order = OrderRepository::getInstance()->getById($params->getOrderId());
        if(is_null($order)) {
            throw new BusinessException(ResponseCode::ORDER_NOT_FOUND);
        }
        // 订单已评论
        if($order->is_comment == 1) {
            throw new BusinessException(ResponseCode::ORDER_STATUS_NOT_COMMENT);
        }
        $customer = CustomerRepository::getInstance()->getById($params->getCustomerId());
        // 处理评论信息
        $commentList = $params->getData();
        foreach ($commentList as $comment)
        {
            $data = [
                'customer_id' => $params->getCustomerId(),
                'avatar_url' => $customer->avatar_url,
                'nickname' => $customer->nickname,
                'goods_id' => $comment['goods_id'],
                'product_id' => $comment['product_id'],
                'score' => $comment['score'],
                'content' => $comment['content'],
                'images' => $comment['uploaded'],
                'specs' => $comment['specs']
            ];
            GoodsRepository::getInstance()->saveComment($data);
        }
        // 更新订单已评论
        OrderRepository::getInstance()->update(['is_comment' => 1], $params->getOrderId());
        return true;
    }

    /**
     * 统计订单数量
     *
     * @return mixed
     */
    public function getCount()
    {
        return OrderRepository::getInstance()->getCountNum();
    }
}
